package com.edfu.commons.email.dao.impl;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.edfu.commons.email.vo.Event;
import com.edfu.commons.email.dao.IEmailEventDAO;
import com.edfu.commons.email.dao.IEmailTemplateDAO;
import com.edfu.commons.email.entities.EmailEventEntity;
import com.edfu.commons.email.exceptions.EventExistsException;
import com.edfu.commons.email.exceptions.EventNotFoundException;
import com.edfu.commons.email.exceptions.TemplateNotFoundException;
import com.edfu.commons.email.util.BeanTransformer;

/**
 * @author naresred
 *
 */
@Component
public class EmailEventDAOImpl implements IEmailEventDAO {
	
	private EntityManager entityManager;

	@PersistenceContext
	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}
	
	@Autowired
	private IEmailTemplateDAO emailTemplateDao;
	
	private static Logger logger = Logger.getLogger(EmailEventDAOImpl.class);
	
	/**
	 * Creates an event. But in real time there is no need to create an event unless there is support for dynamic event creation.
	 * This method throws @EventExistsException if event name already exists in the system
	 * 
	 * @param eventName
	 * @param description
	 * @param isActive
	 * @throws EventExistsException
	 */
	@Override
	public void createEvent(String eventName, String description, boolean isActive) throws EventExistsException {
		logger.debug("Entered [createEvent] method of [EmailEventDAOImpl]");
		
		// Check if eventName already exists in the system
		if (getEventEntity(eventName) != null) {
			logger.info("Event Name " + eventName + " already present in the system");
			throw new EventExistsException("Event already present in the system");
		}
		
		EmailEventEntity ev = new EmailEventEntity();
		ev.setName(eventName);
		ev.setDescription(description);
		ev.setActive(isActive ? 1 : 0);
		
		entityManager.persist(ev);
	}
	
	private void createEvent(Event event) {
		logger.debug("Entered [createEvent] method of [EmailEventDAOImpl]");
		
		if (event != null) {
			try {
				EmailEventEntity ev = new EmailEventEntity();
				ev.setName(event.getEventName());
				ev.setDescription(event.getEventDescription());
				ev.setActive(event.getActive() ? 1 : 0);
				ev.setModel(event.getModelXml());
				entityManager.merge(ev);				
			} catch (Exception e) {
				logger.debug("Exception occured while trying to populate event " + event.getEventName());
			}
		}		
	}
	
	@SuppressWarnings("unchecked")
	private EmailEventEntity getEventEntity(String eventName) {
		Query query = entityManager.createQuery("select e from EmailEventEntity e where e.name = :eventName");
		query.setParameter("eventName", eventName);
		
		List<EmailEventEntity> entityList = query.getResultList();
		EmailEventEntity ev = null;
		
		if (entityList != null && entityList.size() > 0) {
			ev = entityList.get(0);
		}
		
		return ev;	
	}
	
	/**
	 * Deactivates an event. All templates associated to this event will be deactivated.
	 * This method throws @EventNotFoundException if the event is not found in the system 
	 * 
	 * @param eventName
	 * @throws EventNotFoundException
	 * @throws TemplateNotFoundException 
	 */
	@Override
	public void deactivateEvent(String eventName) throws EventNotFoundException, TemplateNotFoundException {
		logger.debug("Entered [deactivateEvent] method of [EmailEventDAOImpl]");
		
		EmailEventEntity ev = getEventEntity(eventName);
		if (ev == null) {
			throw new EventNotFoundException("Event not found in the system");
		}
		
		ev.setActive(0);
		entityManager.merge(ev);
		
		// Now deactivate all active templates specific to this event
		logger.debug("Deactivating all templates to specific to " + eventName + " event");
		emailTemplateDao.deactivateTemplates(eventName);
	}
	
	/**
	 * Retrieves all active events.
	 * 
	 * @return List<Event>
	 */
	@SuppressWarnings("unchecked")
	@Override
	public List<Event> getActiveEvents() {
		logger.debug("Entered [getActiveEvents] method of [EmailEventDAOImpl]");
		
		Query query = entityManager.createQuery("select e from EmailEventEntity e where e.active = :active");
		query.setParameter("active", 1);
		List<EmailEventEntity> eventEntities = query.getResultList();
		
		return BeanTransformer.transformEvents(eventEntities);
	}
	
	/**
	 * Retrieves all events. Even deactivated even will also be fetched.
	 * 
	 * @return List<Event>
	 */
	@SuppressWarnings("unchecked")
	@Override
	public List<Event> getAllEvents() {
		logger.debug("Entered [getAllEvents] method of [EmailEventDAOImpl]");
		
		Query query = entityManager.createQuery("select e from EmailEventEntity e");
		List<EmailEventEntity> eventEntities = query.getResultList();
		
		return BeanTransformer.transformEvents(eventEntities);
	}
	
	/**
	 * Retrieves an event.This method throws @EventNotFoundException if the event is not found in the system
	 * 
	 * @param eventName
	 * @return Event
	 * @throws EventNotFoundException
	 */
	@Override
	public Event getEvent(String eventName) throws EventNotFoundException {
		logger.debug("Entered [getEvents] method of [EmailEventDAOImpl]");
		
		EmailEventEntity ev = getEventEntity(eventName);
		
		if (ev == null) {
			throw new EventNotFoundException("Event not found in the system");
		}
		
		return BeanTransformer.transform(ev);
	}
	
	/**
	 * Populates all events to db. This is one time activity and should not occur every time.
	 * 
	 * @param events
	 */
	@SuppressWarnings({ "unchecked" })
	@Override
	public void populateEvents(List<Event> events) {
		logger.debug("In [populateEvents] method of [EmailEventDAOImpl]");
		EmailEventEntity eventEntity = null;
		for (Event event : events) {
			eventEntity = getEventEntity(event.getEventName());
			if (eventEntity != null) {
				logger.info("Event Name " + event.getEventName() + " already present in the system");
				eventEntity.setName(event.getEventName());
				eventEntity.setDescription(event.getEventDescription());
				eventEntity.setActive(event.getActive() ? 1 : 0);
				eventEntity.setModel(event.getModelXml());
				entityManager.merge(eventEntity);
			} else {
				createEvent(event);
			}			
		}
		
		// Events which are deleted from xml and present in db should be deactivated
		Query query = entityManager.createQuery("select e from EmailEventEntity e");
		List<EmailEventEntity> eventEntities = query.getResultList();
		
		if (eventEntities.size() > events.size()) {
			// Some events are deleted from xml
			StringBuilder sb = new StringBuilder();
			sb.append("select e from EmailEventEntity e where e.name not in(");
			int counter = 1;
			for (Event event : events) {
				sb.append("\'" + event.getEventName() + "\'");
				if (counter < events.size()) {
					sb.append(", ");
					counter++;
				}
			}
			sb.append(")");
			
			Query eventQuery = entityManager.createQuery(sb.toString());
			List<EmailEventEntity> extraEvents = eventQuery.getResultList();
			
			for (EmailEventEntity emailEntity : extraEvents) {
				try {
					deactivateEvent(emailEntity.getName());
				} catch (Exception e) {
					logger.warn("Exception occured while deactivating " + emailEntity.getName() + " Event");
				} 
			}
		}
	}
	
	/**
	 * Activates an event. All templates associated to this event will be activated.
	 * This method throws @EventNotFoundException if the event is not found in the system 
	 * 
	 * @param eventName
	 * @throws EventNotFoundException
	 * @throws TemplateNotFoundException 
	 */
	@Override
	public void activateEvent(String eventName) throws EventNotFoundException, TemplateNotFoundException {
		logger.debug("In [activateEvent] method of [EmailEventDAOImpl]");
		
		EmailEventEntity ev = getEventEntity(eventName);
		if (ev == null) {
			throw new EventNotFoundException("Event not found in the system");
		}
		
		ev.setActive(1);
		entityManager.merge(ev);
		
		// Now activate all active templates specific to this event
		logger.debug("Deactivating all templates to specific to " + eventName + " event");
		emailTemplateDao.activateTemplates(eventName);
	}	

}
